﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Common.Utilities;
using Workflows.Components.Entities.Addresses;

namespace Workflows.Components.Entities.Distances.FieldDistances
{
    public class FuzzyFullAddressComparer:IAttributeDistanceCalcutor 
    {
        private AddressParser _AddrParser;

        #region Implementation of IAttributeComparer

        /// <summary>
        /// load dictionary into memory or read config settings from file
        /// </summary>
        public void InitInMemorySettings()
        {
            this._AddrParser=new AddressParser();
        }

        /// <summary>
        /// return similarity score in [0,1]
        /// 0 indicate no similarity or null match
        /// 1 indicate perfect match
        /// </summary>
        /// <param name="attrValue1"></param>
        /// <param name="attrValue2"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        public double Compare(object attrValue1, object attrValue2, ref MatchResult result)
        {
            result = MatchResult.NullMatch;
            if (attrValue1 == null || attrValue2 == null)
                return 0;

            string strVal1 = attrValue1.ToString();
            string strVal2 = attrValue2.ToString();
            if (strVal1.Length == 0 || strVal2.Length == 0)
                return 0;

            if(strVal1.ToLower().Trim()==strVal2.ToLower().Trim())
            {
                result = MatchResult.PerfectMatch;
                return 1;
            }

            if (StringUtil.LongestCommonSubsequence(strVal1, strVal2) > 10)
            {
                double score = (double)StringUtil.LongestCommonSubsequence(strVal1, strVal2) /
                               Math.Max(strVal1.Length, strVal2.Length);
                if (score > 0.8)
                {
                    result = MatchResult.PositiveMatch;
                    return 0.75;
                }
            }

            Address addr1 = this._AddrParser.ParseAddress(1, strVal1);
            Address addr2 = this._AddrParser.ParseAddress(2, strVal2);

            if(!string.IsNullOrEmpty(addr1.Organization) && 
                !string.IsNullOrEmpty(addr2.Organization) && 
                addr1.Organization.ToLower().Trim()==addr2.Organization.ToLower().Trim())
            {
                result = MatchResult.PerfectMatch;
                return 1;
            }


            if (!string.IsNullOrEmpty(addr1.PostalCode) &&
                !string.IsNullOrEmpty(addr2.PostalCode) &&
                addr1.PostalCode == addr2.PostalCode)
            {
                result = MatchResult.PositiveMatch;
                return 0.75;
            }

            if(!string.IsNullOrEmpty(addr1.Region) && 
                !string.IsNullOrEmpty(addr2.Region) && 
                addr1.Region==addr2.Region)
            {
                result = MatchResult.PositiveMatch;
                return 0.5;
            }

            result = MatchResult.NegativeMatch;
            return 0;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entity1"></param>
        /// <param name="entity2"></param>
        /// <param name="attrMetaData"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        public double Compare(Entity entity1, Entity entity2, AttributeMetaData attrMetaData, ref MatchResult result)
        {
            Debug.Assert(!string.IsNullOrEmpty(attrMetaData.AttributeName));

            string attrName = attrMetaData.AttributeName;
            object attrValue1 = null;
            object attrValue2 = null;
            if (entity1.ComparableAttributes.ContainsKey(attrName))
                attrValue1 = entity1.ComparableAttributes[attrName];
            if (entity2.ComparableAttributes.ContainsKey(attrName))
                attrValue2 = entity2.ComparableAttributes[attrName];
            return this.Compare(attrValue1, attrValue2, ref result);
        }

        /// <summary>
        /// argument to bind attribute name
        /// </summary>
        public string[] ArgumentNames
        {
            get { return new string[]{"Full Address"}; }
        }


        private Dictionary<string, string> _ComparerSettings;
        public Dictionary<string, string> ComparerSettings
        {
            get { return _ComparerSettings; }
            set { _ComparerSettings = value; }
        }

        #endregion
    }
}
